import { Canvg } from "canvg";
import { SVG } from "@svgdotjs/svg.js";

export type ImageMime = "image/png" | "image/jpeg" | "image/bmp";

/**
 * 导出一个用于处理SVG图像的函数
 * 该函数提供了一系列方法，用于解析、格式化和转换SVG图像
 */
export function useSvg() {
  /**
   * 将SVG字符串解析为HTML元素
   * @param {string} svgStr SVG图像的字符串表示
   * @returns {Element} 解析后的SVG元素
   */
  function parserStr2Html(svgStr: string): Element | null {
    const htmlParser = new DOMParser();
    const svgDocument = htmlParser.parseFromString(svgStr, "image/svg+xml");
    return svgDocument.querySelector("svg");
  }

  /**
   * 将SVG元素转换为字符串
   * @param {Element} svg SVG元素
   * @returns {string} 转换后的SVG字符串
   */
  function parserHtml2Str(svg: Element): string {
    return new XMLSerializer().serializeToString(svg);
  }

  /**
   * 格式化SVG字符串，并调整其宽度和高度
   * @param {string} svgStr SVG图像的字符串表示
   * @param {number} width SVG图像的宽度
   * @param {number} height SVG图像的高度
   * @returns {Element} 格式化后的SVG元素
   */
  function fmtSvg(svgStr: string, width: number, height: number) {
    const svgHtml = parserStr2Html(svgStr);
    return SVG(svgHtml).width(width).height(height).node;
  }

  /**
   * 将SVG字符串转换为PNG图像
   * @param {string} svgStr SVG图像的字符串表示
   * @param {number} width 生成的PNG图像的宽度
   * @param {number} height 生成的PNG图像的高度
   * @param {ImageMime} mimeType 图像的MIME类型，默认为“image/png”
   * @returns {Promise<string>} 生成的PNG图像的Base64字符串
   */
  async function svg2Base64(svgStr: string, width: number, height: number, mimeType: ImageMime = "image/png") {
    const svg = fmtSvg(svgStr, width, height);
    const canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext("2d");

    const v = await Canvg.from(ctx!, parserHtml2Str(svg), {
      ignoreAnimation: true
    });

    await v.render();

    return canvas.toDataURL(mimeType);
  }

  /**
   * 合并多个SVG字符串为一个SVG元素
   *
   * @param svgStrs SVG字符串数组
   * @param width 每个SVG的宽度
   * @param height 每个SVG的高度
   * @returns 返回包含合并后SVG字符串、SVG元素、宽度和总高度的对象
   */
  function combineSvg(svgStrs: string[], width: number, height: number) {
    // 创建一个SVG命名空间下的父元素
    const parent = document.createElementNS("http://www.w3.org/2000/svg", "svg");

    // 遍历SVG字符串数组，将每个SVG字符串转换为SVG元素并加入到父元素中
    svgStrs.forEach((svgHtml, index) => {
      // 创建一个SVG命名空间下的组元素（g元素）
      const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
      // 设置组元素的变换属性，以控制每个SVG元素的垂直位置
      group.setAttribute("transform", `translate(0, ${(height + 10) * index})`);
      // 调用fmtSvg函数格式化SVG字符串，并将结果添加到组元素中
      group.appendChild(fmtSvg(svgHtml, width, height));
      // 将组元素添加到父元素中
      parent.appendChild(group);
    });

    // 设置父元素的宽度和高度
    parent.setAttribute("width", width.toString());
    parent.setAttribute("height", ((height + 10) * svgStrs.length).toString());

    // 返回包含合并后SVG字符串、SVG元素、宽度和总高度的对象
    return {
      svgStr: parserHtml2Str(parent),
      svg: parent,
      width: width,
      height: (height + 10) * svgStrs.length
    };
  }

  /**
   * 将多个SVG字符串组合成一个，并导出为Base64格式的图片
   *
   * @param svgStrs - SVG字符串数组，用于组合的SVG内容
   * @param width - 组合后SVG的宽度
   * @param height - 组合后SVG的高度
   * @param mimeType - 图片的MIME类型，默认为"image/png"
   * @returns 返回Promise，解析为Base64格式的图片字符串
   */
  async function combineSvgExportBase64(svgStrs: string[], width: number, height: number, mimeType: ImageMime = "image/png") {
    // 调用combineSvg函数对SVG字符串进行组合
    const svgs = combineSvg(svgStrs, width, height);
    // 将组合后的SVG转换为Base64格式的图片
    return await svg2Base64(svgs.svgStr, svgs.width, svgs.height, mimeType);
  }

  /**
   * 将Base64字符串转换为Blob对象
   * @param {string} base64Data Base64字符串
   * @returns {Blob} 转换后的Blob对象
   */
  function base64ToBlob(base64Data: string): Blob {
    const parts = base64Data.split(";base64,");
    const contentType = parts[0].split(":")[1];
    const raw = window.atob(parts[1]);
    const rawLength = raw.length;
    const uInt8Array = new Uint8Array(rawLength);

    for (let i = 0; i < rawLength; ++i) {
      uInt8Array[i] = raw.charCodeAt(i);
    }

    return new Blob([uInt8Array], { type: contentType });
  }

  /**
   * 下载Base64图像
   * @param {string} base64Data 图像的Base64字符串
   * @param {string} fileName 下载时的文件名
   */
  function downloadBase64Image(base64Data: string, fileName: string) {
    const eleLink = document.createElement("a");
    eleLink.download = fileName;
    eleLink.style.display = "none";
    const blob = base64ToBlob(base64Data);
    const urlObj = window.URL.createObjectURL(blob);
    eleLink.href = urlObj;
    document.body.appendChild(eleLink);
    eleLink.click();
    document.body.removeChild(eleLink);
    window.URL.revokeObjectURL(urlObj);
  }

  return {
    svg2Base64,
    parserHtml2Str,
    parserStr2Html,
    combineSvgExportBase64,
    downloadBase64Image
  };
}
